package servlets;

import exodus.Clip;
import exodus.Food;
import exodus.Water;
import exodus.Weapon;

import javax.servlet.SessionCookieConfig;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Properties;

/**
 * Created with IntelliJ IDEA.
 * User: Joshua
 * Date: 7/30/12
 * Time: 5:18 PM
 * A servlet that retrieves this character's inventory from the database and passes the inventory
 * to an Exodus layer.
 */
public class LoadExodus extends HttpServlet{
    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        HttpSession session = request.getSession();
        //the selected campaign and character
        String character = request.getParameter("character");
        String campaign = request.getParameter("campaign");

        //maps to link weapons to their ammo types
        HashMap<String, ArrayList<Clip>> ammoList;
        HashMap<String, Integer> looseAmmoList;

        //lists for the other necessary items
        ArrayList<Food> foodList;
        ArrayList<Water> waterList;
        ArrayList<Weapon> weaponList;
        ArrayList<Weapon> equippedList;

        //establish the database connection
        try{
            Connection conn = getConnection();

            //get all of this character's inventory items
            foodList = getFood(conn, character, campaign);
            waterList = getWater(conn, character, campaign);
            ammoList = getClips(conn, character, campaign);
            looseAmmoList = getLooseAmmo(conn, character, campaign);
            weaponList = getWeapons(conn, character, campaign);
            equippedList = getEquippedWeapons(conn, character, campaign);

            //set the necessary session variables
            session.setAttribute("foodList", foodList);
            session.setAttribute("waterList", waterList);
            session.setAttribute("ammoList", ammoList);
            session.setAttribute("looseAmmoList", looseAmmoList);
            session.setAttribute("weaponList", weaponList);
            session.setAttribute("equippedList", equippedList);
            session.setAttribute("character", character);
            session.setAttribute("campaign", campaign);

            //pass this info off to the receiving page
            response.sendRedirect("/runSquire.jsp");

        }catch(SQLException sql){
            PrintWriter writer = response.getWriter();
            writer.write("An exception was thrown while attempting to locate "+character+"'s inventory: ");
            writer.write(sql.getMessage());
        }
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException {
        doGet(request, response);
    }

    ///////////////////////////////////////////////////////////////////////////
    //getConnection
    //params: none
    //returns: a database connection
    private Connection getConnection() throws SQLException {

        Connection conn = null;
        Properties connectionProps = new Properties();
        connectionProps.put("user", "steward");
        connectionProps.put("password", "readOnly");


        conn = DriverManager.getConnection(
                "jdbc:postgresql://localhost:5432/squire",
                connectionProps);

        System.out.println("Connected to database");
        return conn;
    }

    ///////////////////////////////////////////////////////////////////////////////
    //getFood
    //parameters: a database connection and the character and campaign
    //returnes: an arraylist of Food objects
    //description: queries the database for all food instances belonging to this
    //character.
    public ArrayList<Food> getFood(Connection conn, String character, String campaign) throws SQLException {
        ArrayList<Food> foodList;
        PreparedStatement foodQuery;
        String query = "select itemid, name, weight, days_to_spoil, rads " +
                "from has_food " +
                "where owner = ? and campaign = ?";

        foodQuery = conn.prepareStatement(query);
        foodQuery.setString(1, character);
        foodQuery.setString(2, campaign);

        ResultSet foodResults = foodQuery.executeQuery();

        foodList = parseFood(foodResults);
        return foodList;
    }

    /////////////////////////////////////////////////////////////////////////////////
    //parseFood
    //parameters: a result set
    //returns: an arraylist of Food objects
    //description: parses the fields from the provided result set to construct Food
    //instances.
    private ArrayList<Food> parseFood(ResultSet foodResults) throws SQLException {
        ArrayList<Food> foodList = new ArrayList<Food>();

        //gather up the food
        while(foodResults.next()){
            String itemid = foodResults.getString("itemid");
            String name = foodResults.getString("name");
            int daysToSpoil = foodResults.getInt("days_to_spoil");
            double weight = foodResults.getDouble("weight");
            int rads = foodResults.getInt("rads");

            Food food = new Food(itemid, name, weight, daysToSpoil, rads);

            foodList.add(food);
        }

        return foodList;
    }

    ///////////////////////////////////////////////////////////////////////////////
    //getWater
    //parameters: a database connection and the character and campaign
    //returnes: an arraylist of Water objects
    //description: queries the database for all water instances belonging to this
    //character.
    public ArrayList<Water> getWater(Connection conn, String character, String campaign) throws SQLException {
        ArrayList<Water> waterList;
        PreparedStatement waterQuery;
        String query = "select itemid, name, quantity, weight, rads " +
                "from has_water " +
                "where owner = ? and campaign = ?";

        waterQuery = conn.prepareStatement(query);
        waterQuery.setString(1, character);
        waterQuery.setString(2, campaign);

        ResultSet waterResults = waterQuery.executeQuery();

        waterList = parseWater(waterResults);
        return waterList;
    }

    /////////////////////////////////////////////////////////////////////////////////
    //parseWater
    //parameters: a result set
    //returns: an arraylist of Water objects
    //description: parses the fields from the provided result set to construct Water
    //instances.
    private ArrayList<Water> parseWater(ResultSet waterResults) throws SQLException {
        ArrayList<Water> waterList = new ArrayList<Water>();

        //gather up the food
        while(waterResults.next()){
            String itemid = waterResults.getString("itemid");
            String name = waterResults.getString("name");
            double quantity = waterResults.getDouble("quantity");
            double weight = waterResults.getDouble("weight");
            int rads = waterResults.getInt("rads");

            Water water = new Water(itemid, name, quantity, weight, rads);

            waterList.add(water);
        }

        return waterList;
    }

    ///////////////////////////////////////////////////////////////////////////////
    //getWeapons
    //parameters: a database connection and the character and campaign
    //returnes: an arraylist of Weapon objects
    //description: queries the database for all weapon instances belonging to this
    //character.
    public ArrayList<Weapon> getWeapons(Connection conn, String character, String campaign) throws SQLException {
        ArrayList<Weapon> weaponList;
        PreparedStatement weaponQuery;
        String query = "select serial, name, ammo, loaded, range " +
                "from has_weapon " +
                "where owner = ? and campaign = ? and equipped=FALSE";

        weaponQuery = conn.prepareStatement(query);
        weaponQuery.setString(1, character);
        weaponQuery.setString(2, campaign);

        ResultSet weaponResults = weaponQuery.executeQuery();

        weaponList = parseWeapon(weaponResults);
        return weaponList;
    }

    /////////////////////////////////////////////////////////////////////////////////
    //parseWeapon
    //parameters: a result set
    //returns: an arraylist of Weapon objects
    //description: parses the fields from the provided result set to construct Weapon
    //instances.
    private ArrayList<Weapon> parseWeapon(ResultSet weaponResults) throws SQLException {
        ArrayList<Weapon> weaponList = new ArrayList<Weapon>();

        //gather up the food
        while(weaponResults.next()){
            String serial = weaponResults.getString("serial");
            String name = weaponResults.getString("name");
            String ammo = weaponResults.getString("ammo");
            String loaded = weaponResults.getString("loaded");
            int range = weaponResults.getInt("range");

            Weapon weapon = new Weapon(serial, name, ammo, loaded, range);

            weaponList.add(weapon);
        }

        return weaponList;
    }

    //////////////////////////////////////////////////////////////////////////////////
    //getEquippedWeapons
    //parameters: the database connection, character and campaign in question
    //returns: a weapon
    //description: retrieves the weapon instance that this character is currently
    //carrying equipped.
    private ArrayList<Weapon> getEquippedWeapons(Connection conn, String character, String campaign) throws SQLException {
        ArrayList<Weapon> equipped;
        PreparedStatement weaponQuery;
        String query = "select serial, name, ammo, loaded, range " +
                "from has_weapon " +
                "where owner = ? and campaign = ? and equipped = TRUE";

        weaponQuery = conn.prepareStatement(query);
        weaponQuery.setString(1, character);
        weaponQuery.setString(2, campaign);

        ResultSet weaponResults = weaponQuery.executeQuery();

        equipped = parseWeapon(weaponResults);

        return equipped;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////
    //getClips
    //parameters: the database connection, character and campaign
    //returns: an Map of Clips
    //description: Retrieves the clips of ammo that this character owns.
    private HashMap<String, ArrayList<Clip>> getClips(Connection conn, String character, String campaign) throws SQLException {
        HashMap<String, ArrayList<Clip>> ammoList;
        PreparedStatement ammoQuery;
        String query = "select serial, weapon, ammo, capacity, quantity " +
                "from has_magazine " +
                "where owner = ? and campaign = ? and capacity > 0";

        ammoQuery = conn.prepareStatement(query);
        ammoQuery.setString(1, character);
        ammoQuery.setString(2, campaign);

        ResultSet ammoResults = ammoQuery.executeQuery();

        ammoList = parseClips(ammoResults);
        return ammoList;
    }

    ///////////////////////////////////////////////////////////////////////////////////////////////////////////
    //parseClips
    //parameters: a Result Set
    //returns: an map of clips
    //description: parses the columns from the Result Set into Clip instances
    private HashMap<String, ArrayList<Clip>> parseClips(ResultSet ammoResults) throws SQLException {
        HashMap<String, ArrayList<Clip>> ammoList = new HashMap<String, ArrayList<Clip>>();

        //gather up the food
        while(ammoResults.next()){
            String serial = ammoResults.getString("serial");
            String weapon = ammoResults.getString("weapon");
            String ammo = ammoResults.getString("ammo");
            int capacity = ammoResults.getInt("capacity");
            int quantity = ammoResults.getInt("quantity");

            Clip clip = new Clip(serial, weapon, ammo, capacity, quantity);

            if(ammoList.containsKey(weapon))
                ammoList.get(weapon).add(clip);
            else{
                ammoList.put(weapon, new ArrayList<Clip>());
                ammoList.get(weapon).add(clip);
            }
        }

        return ammoList;
    }

    //////////////////////////////////////////////////////////////////////////////////////////////////////////
    //getLooseAmmo
    //parameters: the database connection, character and campaign
    //returns: an arraylist of Clip objects
    //description: gets all types of loose ammunition that this character is carrying.
    private HashMap<String, Integer> getLooseAmmo(Connection conn, String character, String campaign) throws SQLException {
        HashMap<String, Integer> ammoList = new HashMap<String, Integer>();
        PreparedStatement ammoQuery;
        String query = "select serial, weapon, ammo, capacity, quantity " +
                "from has_magazine " +
                "where owner = ? and campaign = ? and capacity = 0";

        ammoQuery = conn.prepareStatement(query);
        ammoQuery.setString(1, character);
        ammoQuery.setString(2, campaign);

        ResultSet ammoResults = ammoQuery.executeQuery();

        //gather up the food
        while(ammoResults.next()){
            String ammo = ammoResults.getString("ammo");
            int quantity = ammoResults.getInt("quantity");

            if(ammoList.containsKey(ammo))
                ammoList.put(ammo, ammoList.get(ammo)+quantity);
            else{
                ammoList.put(ammo, quantity);
            }
        }
        return ammoList;
    }
}
